package mongodb

import org.mongodb.scala._
import play.api.libs.json._

import scala.concurrent._

trait ExtendMongodbContext[A] extends NamedMongodbCollection {
  self: PandoraMongodb ⇒

  protected final val _id       = "_id"
  protected final val $set      = "$set"
  protected final val $unset    = "$unset"
  protected final val $inc      = "$inc"
  protected final val $in       = "$in"
  protected final val $regex    = "$regex"
  protected final val $and      = "$and"
  protected final val $or       = "$or"
  protected final val $exists   = "$exists"
  protected final val $push     = "$push"
  protected final val $pushAll  = "$pushAll"
  protected final val $pullAll  = "$pullAll"
  protected final val $pull     = "$pull"
  protected final val $ne       = "$ne"
  protected final val $match    = "$match"
  protected final val $sort     = "$sort"
  protected final val $group    = "$group"
  protected final val $first    = "$first"
  protected final val $sum      = "$sum"
  protected final val $skip     = "$skip"
  protected final val $limit    = "$limit"
  protected final val $addToSet = "$addToSet"
  protected final val $each     = "$each"
  protected final val $position = "$position"

  protected final val justId = MO(_id -> 1)

  protected trait ImplicitObservable[C] extends ObservableImplicits {

    def observable: Observable[C]

    def converter: (C) ⇒ String

    def fetch: Future[Seq[C]] = observable.toFuture()

    def rows(implicit ec: ExecutionContext): Future[Long] = observable.toFuture().map(_.size)
  }

  protected implicit class DocumentObservable[C](val observable: Observable[MO]) extends ImplicitObservable[MO] {

    override val converter: (MO) ⇒ String = (doc) ⇒ doc.toJson
  }

  protected implicit class GenericObservable[C](val observable: Observable[C]) extends ImplicitObservable[C] {

    override val converter: (C) ⇒ String = (doc) ⇒ doc.toString
  }

  protected implicit class ExtendMongodbDocument(mo: MO) {

    def toJsValue: JsValue = Json.parse(mo.toJson)

    def as[T](implicit fmt: Format[T]): T = toJsValue.as[T]
  }

}

//def getLong(key: String): Long = mo.get(key) match {
//  case Some(b: BsonInt32)  ⇒ b.getValue.toLong
//  case Some(b: BsonInt64)  ⇒ b.getValue
//  case Some(b: BsonDouble) ⇒ b.getValue.toLong
//  case Some(b: BsonNumber) ⇒ b.longValue
//  case _                   ⇒ 0L
//}
